use scopeguard::defer;

use bc_base::{
    BlockHeight, BlockId, PublicKeyHashBytes,
    constants::{ALICE_PUBLIC_KEY_HASH, BOB_PUBLIC_KEY_HASH, GENESIS_BLOCK_ID},
};
use bc_manager::LocalTransaction;

use tests::common;

#[tokio::test]
async fn create_tx() {
    let (test_env, tmp_dir) = common::setup("create_tx", false, None, false).await;
    defer! {
        tmp_dir.close().unwrap();
    };

    // do test here
    {
        common::local::add_alice_keypair_to_wallet(test_env.bc_manager.clone()).await;

        // create block
        let prev_block_hash = BlockId::from_hex_str(GENESIS_BLOCK_ID).unwrap();
        let block_height: BlockHeight = 1;
        let miner_pubkey_hash = PublicKeyHashBytes::from_hex_str(ALICE_PUBLIC_KEY_HASH).unwrap();
        let _block_id = common::local::create_block_only_contain_coinbase_and_add_to_blockchain(
            test_env.bc_manager.clone(),
            &prev_block_hash,
            block_height,
            &miner_pubkey_hash,
        )
        .await;

        let bc_manager = test_env.bc_manager.lock().await;
        assert_eq!(bc_manager.block_number().await, 2);
        assert_eq!(bc_manager.transaction_number().await, 2);

        // create tx
        let payer_pubkey_hash = PublicKeyHashBytes::from_hex_str(ALICE_PUBLIC_KEY_HASH).unwrap();
        let payee_pubkey_hash = PublicKeyHashBytes::from_hex_str(BOB_PUBLIC_KEY_HASH).unwrap();
        let tx = bc_manager
            .create_transaction(&payer_pubkey_hash, &payee_pubkey_hash, 100)
            .await
            .unwrap();
        let tx_serialize = tx.serialize();
        let tx_id = tx.calc_tx_id();
        bc_manager
            .process_transaction(tx_id, tx, tx_serialize)
            .await
            .unwrap();

        // check tx
        let r = bc_manager.get_transaction(&tx_id).await.unwrap();
        match r {
            LocalTransaction::TransactionInMemPool(tx) => {
                assert_eq!(tx.calc_tx_id(), tx_id);
            }
            _ => panic!("unexpected"),
        }

        assert_eq!(bc_manager.block_number().await, 2);
        assert_eq!(bc_manager.transaction_number().await, 2);
    }

    common::teardown(test_env).await;
}
